﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Xml;
using com.lover.astd.common.model;

namespace com.lover.astd.common.logic
{
    public class HeroMgr : MgrBase
    {
        public HeroMgr() { _logColor = System.Drawing.Color.LimeGreen; }
        /// <summary>
        /// 0=流程顺利执行完成, 1=洗将完成, 2=出错未完成,3=某种状况,今天已经不需要再进行了
        /// </summary>
        /// <param name="logger">协议处理器</param>
        /// <param name="logger">日志输出器</param>
        /// <param name="hero_id">英雄的ID</param>
        /// <param name="wash_what">洗什么, 每一位代表洗什么, 比如110表示洗统勇,101表示洗统智</param>
        /// <param name="only_free">是否只使用免费洗</param>
        /// <param name="totalCredit">总共多少军工</param>
        /// /// <param name="wash_count">最多洗多少次</param>
        public int startWash(ProtocolMgr protocol, ILogger logger, User user, int hero_id, string wash_what, bool only_free,
            int totalCredit, int wash_count, ref int[] old_attrib)
        {
            int count_washed = 0;
            // 首先获取一下洗属性的状态
            getWashInfo(protocol, logger, user);
            List<Hero> heroes = user.Heroes;
            // 找到要洗点的将,
            Hero hero = null;
            foreach (Hero h in heroes)
            {
                if (h.Id == hero_id) { hero = h; break; }
            }
            if (hero == null)
            {
                logInfo(logger, "未找到要洗点的将, ID为" + hero_id);
                return 2;
            }
            int heroLevel = hero.Level;
            int[] new_attrib = new int[3]{0, 0, 0};
            int credit_per_wash = 0, gold_wash_count = 0, super_wash_count = 0;
            int current_result = getHeroAttributes(protocol, logger, hero, ref heroLevel, ref old_attrib, ref new_attrib);

            // 如果正在洗属性, 则为了简单起见, 先把当前这个操作取消掉
            if (current_result == 0)
            {
                logInfo(logger, "出现未知错误");
                return 2;
            }
            if (current_result == 1) { confirmHeroAttrib(protocol, logger, hero.Id, false); }

            getWashModes(protocol, logger, ref credit_per_wash, ref gold_wash_count, ref super_wash_count);
            // 判断是否需要洗点
            if (!isHeroNeedWash(wash_what, only_free, heroLevel, old_attrib))
            {
                logInfo(logger, "该武将不需要洗属性");
                return 1;
            }
            if (only_free)
            {
                if (gold_wash_count == 0 && super_wash_count == 0)
                {
                    logInfo(logger, "没有免费的洗将次数了");
                    return 3;
                }
                while (gold_wash_count > 0 && count_washed < wash_count)
                {
                    int result = doWash(protocol, logger, hero, 2, wash_what, ref old_attrib, ref new_attrib);
                    if (result == 1) return 2;
                    else if (result == 2) return 1;
                    gold_wash_count--;
                    count_washed++;
                }
                while (super_wash_count > 0 && count_washed < wash_count)
                {
                    int result = doWash(protocol, logger, hero, 3, wash_what, ref old_attrib, ref new_attrib);
                    if (result == 1) return 2;
                    else if (result == 2) return 1;
                    super_wash_count--;
                    count_washed++;
                }
                return 0;
            }
            else
            {
                if (totalCredit < credit_per_wash)
                {
                    logInfo(logger, "洗将军工不足");
                    return 2;
                }
                int current_credit = totalCredit;

                while (current_credit >= credit_per_wash && count_washed < wash_count)
                {
                    int result = doWash(protocol, logger, hero, 0, wash_what, ref old_attrib, ref new_attrib);
                    if (result == 1) return 2;
                    else if (result == 2) return 1;
                    current_credit -= credit_per_wash;
                    count_washed++;
                }
                return 0;
            }
        }
        /// <summary>
        /// 0=成功洗了属性, 1=出错并返回, 2=洗完了返回
        /// </summary>
        /// <param name="hero"></param>
        /// <param name="wash_mode"></param>
        /// <param name="old_attrib"></param>
        /// <param name="new_attrib"></param>
        /// <returns></returns>
        private int doWash(ProtocolMgr protocol, ILogger logger, Hero hero, int wash_mode, string wash_what, ref int[] old_attrib, ref int[] new_attrib)
        {
            string wash_mode_str = "";
            if (wash_mode == 0) wash_mode_str = "军功";
            else if (wash_mode == 1) wash_mode_str = "加强";
            else if (wash_mode == 2) wash_mode_str = "白金";
            else if (wash_mode == 3) wash_mode_str = "至尊";
            bool wash_success = washHero(protocol, logger, hero, wash_mode, ref new_attrib);

            if (!wash_success)
            {
                logInfo(logger, "洗属性失败, 顺延至下个半小时");
                return 1;
            }
            else
            {
                string desc = String.Format("为武将[{0}]{1}洗属性, 获得属性[统:{2}, 勇:{3}, 智:{4}], 原属性为[统:{5}, 勇:{6}, 智:{7}]",
                    hero.Name, wash_mode_str, new_attrib[0], new_attrib[1], new_attrib[2], old_attrib[0], old_attrib[1], old_attrib[2]);
                logInfo(logger, desc);
                bool only_free = wash_mode != 0;
                if (isNewAttribBetter(logger, wash_what, only_free, old_attrib, new_attrib))
                {

                    // 分配属性
                    confirmHeroAttrib(protocol, logger, hero.Id, true);
                    for (int i = 0; i < 3; i++) old_attrib[i] = new_attrib[i];
                    // 判断是否已经洗将完成
                    if (!isHeroNeedWash(wash_what, only_free, hero.Level, old_attrib))
                    {
                        logInfo(logger, String.Format("武将[{0}]洗属性完毕", hero.Name));
                        return 2;
                    }
                }
                else
                {
                    confirmHeroAttrib(protocol, logger, hero.Id, false);
                }
            }
            return 0;
        }
        private bool isHeroNeedWash(string wash_attrib, bool only_free, int hero_level, int[] old_attrib)
        {
            int attrib_max = hero_level + 20;
            bool some_full = false, all_full = true;
            for (int i = 0; i < wash_attrib.Length; i++)
            {
                if (wash_attrib[i].Equals('1') && old_attrib[i] >= attrib_max)
                {
                    some_full = true;
                    break;
                }
            }
            for (int i = 0; i < wash_attrib.Length; i++)
            {
                if (wash_attrib[i].Equals('1') && old_attrib[i] < attrib_max)
                {
                    all_full = false;
                    break;
                }
            }
            if (only_free)
            {
                if (all_full) return false;
                return true;
            }
            else
            {
                if (some_full) return false;
                return true;
            }

        }
        private bool isNewAttribBetter(ILogger logger, string wash_attrib, bool only_free, int[] old_attrib, int[] new_attrib)
        {
            // if all new attrib  > old attrib, must better
            int[] _new_minus_old = new int[3];
            for (int i = 0; i < wash_attrib.Length; i++)
            {
                if (wash_attrib[i].Equals('1')) _new_minus_old[i] = new_attrib[i] - old_attrib[i];
                else _new_minus_old[i] = 0;
            }
            int total = _new_minus_old[0] + _new_minus_old[1] + _new_minus_old[2];
            if (only_free) // 只用免费洗, 肯定是补点, 考虑的是新属性总数大于老属性
            {
                if (total > 0) return true;
                else return false;
            }
            else // 正常洗, 尽量让需要洗的属性之间差值在20以内
            {
                // 如果都大于, 肯定ok
                if (new_attrib[0] >= old_attrib[0] && new_attrib[1] >= old_attrib[1]
                    && new_attrib[2] >= old_attrib[2]) return true;
                else
                {
                    // 判断是否需要洗的属性差值都在20以内, 如果是的话, 那么判断新属性总和大于老属性就ok
                    // 找到需要洗的属性中最大的和最小的, 判断他们的差值是否在20以内
                    int max = -1, min = 10000, max_i = -1, min_i = -1;
                    for (int i = 0; i < 3; i++)
                    {
                        if (wash_attrib[i].Equals('1') && old_attrib[i] > max)
                        {
                            max = old_attrib[i]; max_i = i;
                        }
                        if (wash_attrib[i].Equals('1') && old_attrib[i] < min)
                        {
                            min = old_attrib[i]; min_i = i;
                        }
                    }
                    if (max - min < 20)
                    {
                        if (total > 0) return true;
                        else return false;
                    }
                    else // 如果属性值差大于20的话, 那么需要最小值的那个属性是上升的才ok
                    {
                        logInfo(logger, "需要洗的属性值中最大最小值相差已经大于20, 必须最小属性提升了才能替换");
                        if (_new_minus_old[min_i] > 0)
                        {
                            // 除了最小属性必须提升之外, 还必须保证新属性之间的差值不能大于20, 否则也不能替换
                            max = -1; min = 10000; max_i = -1; min_i = -1;
                            for (int i = 0; i < 3; i++)
                            {
                                if (wash_attrib[i].Equals('1') && new_attrib[i] > max)
                                {
                                    max = new_attrib[i]; max_i = i;
                                }
                                if (wash_attrib[i].Equals('1') && new_attrib[i] < min)
                                {
                                    min = new_attrib[i]; min_i = i;
                                }
                            }
                            if (max - min < 20) return true;
                            return false;
                        }
                        else return false;
                    }
                }
            }
        }
        public void getWashModes(ProtocolMgr protocol, ILogger logger, ref int creditCostToWash, ref int goldWashCount, ref int superWashCount)
        {
            string url = "/root/general!getRefreshGeneralInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取武将洗属性参数");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            XmlNode gold_wash_times_node = xml.SelectSingleNode("/results/freebaijintime");
            if (gold_wash_times_node != null) Int32.TryParse(gold_wash_times_node.InnerText, out goldWashCount);
            else goldWashCount = 0;
            XmlNode super_wash_times_node = xml.SelectSingleNode("/results/freezizuntime");
            if (super_wash_times_node != null) Int32.TryParse(super_wash_times_node.InnerText, out superWashCount);
            else superWashCount = 0;
            XmlNodeList nodes = xml.SelectNodes("/results/refreshmodel");
            foreach (XmlNode node in nodes)
            {
                XmlNodeList childs = node.ChildNodes;
                string name = "", cost = "";
                int free_times = 0;
                foreach (XmlNode child in childs)
                {
                    if (child.Name == "name") name = child.InnerText;
                    else if (child.Name == "cost") cost = child.InnerText;
                    else if (child.Name == "freetimes") Int32.TryParse(child.InnerText, out free_times);
                }
                if (name.Contains("普通洗属性") || name.Contains("普通洗屬性"))
                {
                    string coststr = cost.Replace("军功", "");
                    Int32.TryParse(coststr, out creditCostToWash);
                }
            }
        }
        public void getWashInfo(ProtocolMgr protocol, ILogger logger, User user)
        {
            string url = "/root/general!getTrainGeneralInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取武将信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            XmlNode results = xml.SelectSingleNode("/results");
            XmlNodeList childs = results.ChildNodes;
            List<Hero> heroes = user.Heroes;
            List<int> heroIds = new List<int>();
            foreach (XmlNode child in childs)
            {
                if (child.Name == "general")
                {
                    int heroId = 0;
                    XmlNode id_node = child.SelectSingleNode("generalid");
                    if (id_node != null) Int32.TryParse(id_node.InnerText, out heroId);
                    if (heroId == 0) continue;
                    heroIds.Add(heroId);
                    XmlNodeList general_childs = child.ChildNodes;
                    Hero hero = getHero(heroes, heroId);
                    if (hero == null)
                    {
                        hero = new Hero();
                        heroes.Add(hero);
                    }
                    hero.fillValues(general_childs);
                }
            }
            for (int i = 0; i < heroes.Count; i++)
            {
                int heroId = heroes[i].Id;
                if (!heroIds.Contains(heroId)) { heroes.RemoveAt(i); i--; }
            }
        }
        private Hero getHero(List<Hero> heroes, int heroId)
        {
            for (int i = 0, len = heroes.Count; i < len; i++) { if (heroes[i].Id == heroId) return heroes[i]; }
            return null; 
        }
        /// <summary>
        /// 返回值: 0=出现错误, 1=已经在洗属性, 需要直接确定, 2=成功获得属性
        /// </summary>
        /// <param name="heroId"></param>
        /// <returns>0=出现错误, 1=已经在洗属性, 需要直接确定, 2=成功获得属性</returns>
        private int getHeroAttributes(ProtocolMgr protocol, ILogger logger, Hero h, ref int heroLevel, ref int[] old_attrib, ref int[] new_attrib)
        {
            if (h == null) return 0;
            //string url = "/root/general!getRefreshGeneralInfo.action";
            string url = "/root/general!getRefreshGeneralDetailInfo.action";
            string data = "generalId=" + h.Id;
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "获取武将洗属性信息");
            if (result == null || !result.CmdSucceed) return 0;
            XmlDocument xml = result.CmdResult;
            XmlNode level_node = xml.SelectSingleNode("/results/generaldto/generallevel");
            if (level_node != null)
            {
                int level = 0;
                if (Int32.TryParse(level_node.InnerText, out level))
                {
                    h.Level = level;
                    heroLevel = level;
                }
            }

            XmlNode general_node = xml.SelectSingleNode("/results/general");
            if (general_node == null) return 0;
            XmlNode oldattr_node = xml.SelectSingleNode("/results/general/originalattr");
            foreach (XmlNode child in oldattr_node.ChildNodes)
            {
                if (child.Name == "plusleader") old_attrib[0] = Int32.Parse(child.InnerText);
                else if (child.Name == "plusforces") old_attrib[1] = Int32.Parse(child.InnerText);
                else if (child.Name == "plusintelligence") old_attrib[2] = Int32.Parse(child.InnerText);
            }
            XmlNode newattr_node = xml.SelectSingleNode("/results/general/newattr");
            if (newattr_node != null) // 表示正在洗属性
            {
                foreach (XmlNode child in newattr_node.ChildNodes)
                {
                    if (child.Name == "plusleader") new_attrib[0] = Int32.Parse(child.InnerText);
                    else if (child.Name == "plusforces") new_attrib[1] = Int32.Parse(child.InnerText);
                    else if (child.Name == "plusintelligence") new_attrib[2] = Int32.Parse(child.InnerText);
                }

                return 1;
            }
            else
            {
                return 2;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="heroId"></param>
        /// <param name="washMode">0=军功, 1=加强, 2=白金, 3=至尊</param>
        /// <returns></returns>
        private bool washHero(ProtocolMgr protocol, ILogger logger, Hero h, int washMode, ref int[] new_attrib)
        {
            if (h == null) return false;
            string url = "/root/general!refreshGeneral.action";
            string data = String.Format("generalId={0}&refreshModel={1}", h.Id, washMode);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, String.Format("为[{0}]洗属性", h.Name));
            if (result == null || !result.CmdSucceed) return false;
            XmlDocument xml = result.CmdResult;
            XmlNode node = xml.SelectSingleNode("/results/general");
            if (node == null) return false;
            XmlNodeList childs = node.ChildNodes;
            foreach (XmlNode child in childs)
            {
                if (child.Name == "plusleader") new_attrib[0] = Int32.Parse(child.InnerText);
                else if (child.Name == "plusforces") new_attrib[1] = Int32.Parse(child.InnerText);
                else if (child.Name == "plusintelligence") new_attrib[2] = Int32.Parse(child.InnerText);
            }

            return true;
        }
        private void confirmHeroAttrib(ProtocolMgr protocol, ILogger logger, int heroId, bool accept)
        {
            string url = "/root/general!refreshGeneralConfirm.action";
            string data = String.Format("choose={0}&generalId={1}", accept ? 1 : 0, heroId);
            com.lover.astd.common.model.ServerResult result = protocol.postXml(url, data, "确认武将洗属性信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            if (accept)
            {
                XmlNode msg_node = xml.SelectSingleNode("/results/message");
                logInfo(logger, msg_node.InnerText);
            }
            else
            {
                logInfo(logger, "保持原有属性不变");
            }
        }
        /// <summary>
        /// 获取所有已招募英雄
        /// </summary>
        public void getAllHeros(ProtocolMgr protocol, ILogger logger, ref User user)
        {
            string url = "/root/general!getTrainGeneralInfo.action";
            com.lover.astd.common.model.ServerResult result = protocol.getXml(url, "获取武将信息");
            if (result == null || !result.CmdSucceed) return;
            XmlDocument xml = result.CmdResult;
            XmlNode results = xml.SelectSingleNode("/results");
            int cd, tfnumber, tfcredit = 0;
            XmlNode cdnode = xml.SelectSingleNode("/results/cd"); // 单位:毫秒
            Int32.TryParse(cdnode.InnerText, out cd);
            user.TuFeiCd = cd;
            XmlNode cdflagnode = xml.SelectSingleNode("/results/cdflag");
            user.TuFeiCdFlag = cdflagnode.InnerText == "1";
            XmlNode tfnode = xml.SelectSingleNode("/results/tfnum");
            Int32.TryParse(tfnode.InnerText, out tfnumber);
            user.TufeiNumber = tfnumber;
            
            XmlNodeList childs = results.ChildNodes;
            List<Hero> heroes = user.Heroes;
            List<int> heroIds = new List<int>();
            foreach (XmlNode child in childs)
            {
                if (child.Name == "general")
                {
                    int heroId = 0;
                    XmlNode id_node = child.SelectSingleNode("generalid");
                    if (id_node != null) Int32.TryParse(id_node.InnerText, out heroId);
                    if (heroId == 0) continue;
                    heroIds.Add(heroId);
                    XmlNodeList general_childs = child.ChildNodes;
                    Hero hero = getHero(heroes, heroId);
                    if (hero == null)
                    {
                        hero = new Hero();
                        heroes.Add(hero);
                    }
                    hero.TrainPositionId = 0;
                    hero.fillValues(general_childs);

                    XmlNode creditnode = child.SelectSingleNode("jyungong");
                    if (creditnode != null) Int32.TryParse(creditnode.InnerText, out tfcredit);
                    if(tfcredit > 0) user.TufeiCredit = tfcredit;
                }
            }
            for (int i = 0; i < heroes.Count; i++)
            {
                int heroId = heroes[i].Id;
                if (!heroIds.Contains(heroId)) { heroes.RemoveAt(i); i--; }
            }
            foreach (XmlNode child in childs)
            {
                if (child.Name == "trainpos")
                {
                    XmlNodeList train_childs = child.ChildNodes;
                    int general_id = 0, trainpos_id = 0;
                    foreach (XmlNode sub in train_childs)
                    {
                        if (sub.Name == "traingeneralid") general_id = Int32.Parse(sub.InnerText);
                        else if (sub.Name == "trainposid") trainpos_id = Int32.Parse(sub.InnerText);
                    }
                    if (general_id > 0)
                    {
                        Hero hero = getHero(heroes, general_id);
                        hero.TrainPositionId = trainpos_id;
                    }
                }
            }
        }
        public bool removeTrainCd(ProtocolMgr proto,  ILogger logger)
        {
            string url = "/root/general!cdRecoverConfirm.action";
            com.lover.astd.common.model.ServerResult result = proto.getXml(url, "秒突飞cd");
            if (result == null || !result.CmdSucceed) return false;
            XmlDocument xml = result.CmdResult;
            logInfo(logger, "秒突飞CD");
            return true;
        }
        /// <summary>
        /// 突飞英雄
        /// </summary>
        /// <param name="heroId"></param>
        /// <returns></returns>
        public bool trainHero(ProtocolMgr proto,  ILogger logger, User user, int heroId)
        {
            string url = "/root/general!guideGeneral.action";
            string data = String.Format("guideModel=1&generalId={0}", heroId);
            List<Hero> heroes = user.Heroes;
            Hero hero = getHero(heroes, heroId);
            if (hero == null) return false;
            if (hero.TrainPositionId == 0)
            {
                //武将还没有开始训练, 忽略
                return false;
            }
            com.lover.astd.common.model.ServerResult result = proto.postXml(url, data, "训练武将");
            if (result == null)
            {
                return false;
            }
            XmlDocument xml = result.CmdResult;
            XmlNodeList childs = xml.SelectSingleNode("/results").ChildNodes;
            int formerLevel = hero.Level, formerShiftLevel = hero.ShiftLevel;
            List<int> heroIds = new List<int>();
            int exp = 0;
            foreach (XmlNode child in childs)
            {
                if (child.Name == "effect")
                {
                    XmlNodeList effect_childs = child.ChildNodes;
                    foreach (XmlNode effnode in effect_childs)
                    {
                        if (effnode.Name == "guideexp") exp = Int32.Parse(effnode.InnerText);
                    }
                }
                else if (child.Name == "general")
                {
                    int hid = 0;
                    XmlNode id_node = child.SelectSingleNode("generalid");
                    if (id_node != null) Int32.TryParse(id_node.InnerText, out hid);
                    if (hid == 0) continue;
                    heroIds.Add(hid);
                    XmlNodeList general_childs = child.ChildNodes;
                    Hero h = getHero(heroes, hid);
                    if (h == null)
                    {
                        h = new Hero();
                        heroes.Add(h);
                    }
                    h.TrainPositionId = 0;
                    h.fillValues(general_childs);
                    int tfcredit = 0;
                    XmlNode creditnode = child.SelectSingleNode("jyungong");
                    if(creditnode != null) Int32.TryParse(creditnode.InnerText, out tfcredit);
                    if (tfcredit > 0) user.TufeiCredit = tfcredit;
                }
            }
            for (int i = 0; i < heroes.Count; i++)
            {
                int hid = heroes[i].Id;
                if (!heroIds.Contains(hid)) { heroes.RemoveAt(i); i--; }
            }
            int cd, tfnumber;
            XmlNode cdnode = xml.SelectSingleNode("/results/cd"); // 单位:毫秒
            if (cdnode != null) Int32.TryParse(cdnode.InnerText, out cd);
            else cd = 0;
            XmlNode cdflagnode = xml.SelectSingleNode("/results/cdflag");
            if (cdflagnode != null) user.TuFeiCdFlag = cdflagnode.InnerText == "1";
            XmlNode tfnode = xml.SelectSingleNode("/results/tfnum");
            if (tfnode != null) Int32.TryParse(tfnode.InnerText, out tfnumber);
            else tfnumber = 0;

            user.TuFeiCd = cd; user.TufeiNumber = tfnumber; 

            string loginfo = String.Format("突飞武将 [{0}], 获得经验 [{1}]", hero.Name, exp);
            if (tfnumber > 0) loginfo += String.Format(", 剩余突飞令 [{0}]个", tfnumber);
            if (formerLevel != hero.Level) loginfo += String.Format(", 武将升级 {0}=>{1}", formerLevel, hero.Level);
            if (formerShiftLevel != hero.ShiftLevel) loginfo += String.Format(", 将星增加{0}", hero.ShiftLevel - formerShiftLevel);
            logInfo(logger, loginfo);
            return true;
        }
    }
}
